﻿// by Shimohana
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;
using AzukiMap.Map;
using AzukiMap.MapSource;
using AzukiMap.Renderer;
using GeoAPI.Geometries;

namespace AzukiMap.Layer
{
    public class EditVectorLayer : LocalVectorLayer
    {
        private readonly MapCoordinate _mapCoordinate;
        private readonly Canvas _rootCanvas; // TODO 
        private EditVectorMode _editVectorMode;

        public IPoint DragStartPoint
        {
            get; set;
        }

        public EditVectorData DragVectorData
        {
            get; set;
        }

        public EditVectorLayer(MapCoordinate mapCoordinate, Canvas rootCanvas, LocalVectorSource vectorSource,
                               string name)
        {
            LocalVectorSource = vectorSource;
            Name = name;

            _mapCoordinate = mapCoordinate;
            this._rootCanvas = rootCanvas;

            EditVectorMode = EditVectorMode.NoEdit;

            DefaultStyle = AzukiMapSettings.EDIT_LAYER_DEFAULT_STYLE;
            FeatureStyle = AzukiMapSettings.EDIT_LAYER_FEATURE_STYLE;
            EditNodeStyle = AzukiMapSettings.EDIT_LAYER_EDIT_POINT_STYLE;
            EditPointStyle = AzukiMapSettings.EDIT_LAYER_EDIT_POINT_STYLE;
            EditLineStyle = AzukiMapSettings.EDIT_LAYER_EDIT_LINE_STYLE;
            EditPolygonStyle = AzukiMapSettings.EDIT_LAYER_EDIT_POLYGON_STYLE;
            DivideNodeStyle = AzukiMapSettings.EDIT_LAYER_DIVIDE_POINT_STYLE;

            IsSelectable = true;
            ElementSelected += EditVectorLayer_ElementSelected;
        }

        public IVectorStyle FeatureStyle { get; set; }
        public IVectorStyle EditNodeStyle { get; set; }
        public IVectorStyle EditPointStyle { get; set; }
        public IVectorStyle EditLineStyle { get; set; }
        public IVectorStyle EditPolygonStyle { get; set; }
        public IVectorStyle DivideNodeStyle { get; set; }

        public bool IsDrag { get; set; }

        public EditVectorMode EditVectorMode
        {
            get { return _editVectorMode; }
            set
            {
                if (EditVectorSource != null)
                {
                    EditVectorSource.EditVectorMode = value;
                    _editVectorMode = value;
                }
            }
        }

        public EditVectorSource EditVectorSource
        {
            get { return (EditVectorSource) VectorSource; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                base.VectorSource = value;
            }
        }

        private void EditVectorLayer_ElementSelected(VectorLayer layer, int id, FrameworkElement element, bool isMulti)
        {
            string t = element.ToString();
            if (element.GetType() == typeof (Path))
            {
                EditVectorMode = EditVectorMode.Edit;
                EditVectorSource.SetWorkFeature();
                layer.ClearSelectedElements();
            }
        }

        protected override IVectorStyle GetStyle(LocalVectorData item)
        {
            var eitem = item as EditVectorData;
            if (eitem == null) base.GetStyle(item);

            switch (eitem.EditFeatureType)
            {
                case EditFeatureType.Feature:
                    return FeatureStyle;
                case EditFeatureType.EditPoint:
                    return EditNodeStyle;
                case EditFeatureType.EditLine:
                    return EditLineStyle;
                case EditFeatureType.EditPolygon:
                    return EditPolygonStyle;
                case EditFeatureType.DivPoint:
                    return DivideNodeStyle;
            }

            return DefaultStyle;
        }

        protected override void SetElementAttr(LocalVectorData item, List<FrameworkElement> elems)
        {
            base.SetElementAttr(item, elems);

            var editItem = item as EditVectorData;
            if (editItem == null) return;

            SetElementAttr(elems, editItem);
        }

        private void SetElementAttr(IEnumerable<FrameworkElement> elems, EditVectorData editItem)
        {
            foreach (FrameworkElement fe in elems)
            {
                fe.Resources.Add("EditVectorData", editItem);
                fe.IsHitTestVisible = true;

                if (EditVectorMode == EditVectorMode.Edit)
                {
                    switch (editItem.EditFeatureType)
                    {
                        case EditFeatureType.EditPoint:
                        case EditFeatureType.DivPoint:
                        //case EditFeatureType.EditPolygon:
                        case EditFeatureType.EditLine:
                            fe.Cursor = Cursors.Hand;
                            fe.MouseLeftButtonDown += FeMouseLeftButtonDown;
                            break;
                    }
                }
            }
        }

        public void FeatureDrag(Point p)
        {
            if (IsDrag)
            {
                DragDraw(p);
            }
        }

        public void FeatureDragEnd(Point p)
        {
            if (IsDrag)
            {
                IsDrag = false;

                DragDraw(p);
            }
        }

        private void DragDraw(Point p)
        {
            IPoint point = _mapCoordinate.GetGeoPointFromPixel(p.X, p.Y);
            if (DragVectorData != null)
            {
                switch (DragVectorData.EditFeatureType)
                {
                    case EditFeatureType.EditPoint:
                        if (DragVectorData.Geometry is IPoint)
                        {
                            var gp = DragVectorData.Geometry as IPoint;
                            gp.X = point.X;
                            gp.Y = point.Y;
                        }
                        break;

                    // Move feature
                    /*
                    case EditFeatureType.EditLine:
                    case EditFeatureType.EditPolygon:
                        EditVectorSource.MovePoints(point.X - DragStartPoint.X, point.Y - DragStartPoint.Y);
                        DragStartPoint = point;
                        break;
                    */
                }
            }

            EditVectorSource.SetWorkFeature();
            Draw();
        }

        private void FeMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var fe = sender as FrameworkElement;
            if (fe != null)
            {
                IsDrag = true;
                DragVectorData = (EditVectorData) fe.Resources["EditVectorData"];
                if (DragVectorData != null)
                {
                    if (DragVectorData.EditFeatureType == EditFeatureType.DivPoint)
                    {
                        DragVectorData.EditFeatureType = EditFeatureType.EditPoint;
                    }
                }
                Point p = e.GetPosition(_rootCanvas);
                DragStartPoint = _mapCoordinate.GetGeoPointFromPixel(p.X, p.Y);
            }
        }
    }
}